import { useEffect } from "react";
import { message, Table, Popconfirm, Alert } from "antd";
import { Button, Card as SemiCard } from "@douyinfe/semi-ui";
import { IconRefresh } from "@douyinfe/semi-icons";
import { useModel, history } from "umi";
import { useReactive } from "ahooks";
import dayjs from "dayjs";
import { v4 as uuidv4 } from "uuid";

import {
    ApplicationByAiUuid,
    AllApplicationsWithClients,
    AddApplication,
    UpdateApplication,
    CreateApplicationType,
    UpdateApplicationType,
} from "../_graphql/applications";
import { CreateApplicationRole } from "../_graphql/roles";

let isSameOrBefore = require("dayjs/plugin/isSameOrBefore");
dayjs.extend(isSameOrBefore);

const { Column } = Table;

const NewApplications = () => {
    const { remoteData, windowInnerHeight, graphqlFetch } = useModel("global");
    const { organizationUuid, organizationInfo, gateways } = useModel("organization.info");

    const state = useReactive({
        loading: false,
        remoteApplications: [],
        localApplications: [],
        applications: [],
        newApplications: [],
        newApplicationClients: [],
        totalCount: 0,
        pageSize: 20,
        page: 1,
        errorsInfo: [],
    });

    const loadRemoteApplications = async () => {
        if (state.remoteApplications.length === 0) {
            let remote = await remoteData({
                object: "bnt-application-operation-center-service",
                serviceName: "/customer/organization/application/getAll",
                params: { oiUuid: organizationUuid },
            });
            state.remoteApplications = remote?.applications || [];
        }
        return state.remoteApplications;
    };

    const loadLocalApplications = async () => {
        let res = await graphqlFetch({
            query: AllApplicationsWithClients,
            variables: {},
        });
        state.localApplications = res?.a?.nodes || [];
        return state.localApplications;
    };

    const loadApplications = async () => {
        state.loading = true;
        let remoteApplications = await loadRemoteApplications();
        let localApplications = await loadLocalApplications();

        state.newApplications = remoteApplications.filter((item) => localApplications.findIndex((_item) => _item.aiUuid === item.aiUuid) === -1);
        let oldApplications = remoteApplications.filter((item) => localApplications.findIndex((_item) => _item.aiUuid === item.aiUuid) !== -1);

        let clients = [];
        localApplications.forEach((app) => {
            let remote = oldApplications.find((item) => item.aiUuid === app.aiUuid);
            let local = localApplications.find((item) => item.aiUuid === app.aiUuid);

            if (remote?.ApplicationTypes && Array.isArray(remote?.ApplicationTypes)) {
                for (let index = 0; index < remote?.ApplicationTypes.length; index++) {
                    const remoteClient = remote?.ApplicationTypes[index];
                    if (local.aiClie?.nodes && Array.isArray(local.aiClie.nodes)) {
                        let localClient = local.aiClie.nodes.find((item) => item.atType === remoteClient.atType);
                        if (localClient && localClient.atVeno !== remoteClient.atVeno) {
                            clients.push({
                                ...remote,
                                ...remoteClient,
                                oldVeno: localClient.atVeno,
                                operator: "update",
                            });
                        } else if (!localClient) {
                            clients.push({ ...remote, ...remoteClient, operator: "add" });
                        }
                    } else {
                        clients.push({ ...remote, ...remoteClient, operator: "add" });
                    }
                }
            }
        });

        state.newApplicationClients = clients;

        state.loading = false;

        if (state.newApplications.length === 0 && state.newApplicationClients.length === 0) return history.replace("/role");
    };

    useEffect(() => {
        loadApplications();
    }, []);

    const checkDependentedDatabase = (app) => {
        // 判断应用依赖的数据库版本是否满足
        let errors = [];
        let deploiedDatabases = [];

        gateways.forEach((item) => {
            if (app.aiGwty.includes(item.networkType)) deploiedDatabases = deploiedDatabases.concat(item.deploiedDatabases);
        });

        for (let i = 0; i < app.aiData.length; i++) {
            const aiData = app.aiData[i];
            // 检查是否已部署
            let databases = deploiedDatabases.filter((item) => item.databaseName === aiData.databaseName);
            if (databases.length === 0) {
                errors.push(`应用依赖的数据库模式(${aiData.databaseName})没有部署, 不能同步应用信息`);
                break;
            }
            // 检查已部署的版本
            databases.forEach((item) => {
                if (aiData.versionNo > item.versionNo) {
                    errors.push(`应用依赖的数据库模式(${aiData.databaseName})版本(${aiData.versionNo})大于组织部署的版本(${item.versionNo}), 不能同步应用信息`);
                }
            });
        }

        state.errorsInfo = errors;

        return errors.length === 0;
    };

    const handleAddNewApplication = async (app) => {
        let isOk = checkDependentedDatabase(app);
        if (!isOk) return;

        // 同步应用角色信息
        let roleRes = await graphqlFetch({
            query: `query MyQuery($arName: String!) { a: applicationRoleByArName(arName: $arName) { arUuid, arName } }`,
            variables: { arName: app.aiObje },
        });
        if (!roleRes) return;

        if (!roleRes?.a?.arUuid) {
            let res = await graphqlFetch({
                query: CreateApplicationRole,
                variables: {
                    arUuid: uuidv4(),
                    arName: app.aiObje,
                    arCrti: new Date().getUTCTime(),
                },
            });
            if (!res) return;
        }

        let local = await graphqlFetch({
            query: ApplicationByAiUuid,
            variables: { aiUuid: app.aiUuid },
        });

        local = local?.a || null;

        let saveData = {
            aiUuid: app.aiUuid,
            aiName: app.aiName,
            aiClas: app.aiClas,
            aiDesc: app.aiDesc || "",
            aiType: app.aiType,
            aiAona: app?.aiObje,
            aiSduu: app?.aiSduu,
            aiSdna: app?.aiSdna,
            aiScms: app?.aiScms,
            aiSpuu: app?.spUscc || null,
            aiSpna: app?.spName || null,
            aiLogn: app?.aiLogn,
            aiFree: app?.isFree,
            aiStda: app?.aiStda,
            aiEnda: app?.aiEnda,
        };

        if (local) {
            let res = await graphqlFetch({ query: UpdateApplication, variables: saveData });
            if (res) {
                message.success("成功更新应用信息");
                const localClients = local?.clients?.nodes || [];
                if (app.ApplicationTypes && Array.isArray(app.ApplicationTypes)) {
                    for (let index = 0; index < app.ApplicationTypes.length; index++) {
                        const client = app.ApplicationTypes[index];
                        let query = "";
                        if (localClients.findIndex((item) => item.atType === client.atType) === -1) {
                            query = CreateApplicationType;
                        } else {
                            query = UpdateApplicationType;
                        }
                        await graphqlFetch({
                            query,
                            variables: client,
                            hashs: { pins: [client.atHash] },
                        });
                    }
                }
                state.newApplications = state.newApplications.filter((item) => item.aiUuid !== app.aiUuid);
            }
        } else {
            let res = await graphqlFetch({ query: AddApplication, variables: saveData });
            if (res) {
                message.success("成功添加应用");
                if (app.ApplicationTypes && Array.isArray(app.ApplicationTypes)) {
                    for (let index = 0; index < app.ApplicationTypes.length; index++) {
                        const client = app.ApplicationTypes[index];
                        await graphqlFetch({ query: CreateApplicationType, variables: client });
                    }
                }
                state.newApplications = state.newApplications.filter((item) => item.aiUuid !== app.aiUuid);
            }
        }
    };

    const handleUpdateApplicationType = async (app, operate) => {
        let isOk = checkDependentedDatabase(app);
        if (!isOk) return;

        let saveData = {
            aiUuid: app.aiUuid,
            atType: app.atType,
            atDesc: app.atDesc,
            atHash: app.atHash,
            atIcon: app.atIcon,
            atPath: app.atPath,
            atPbti: app.atPbti,
            atSize: app.atSize,
            atVeno: app.atVeno,
            atBgco: app.atBgco,
            atOpen: app.atOpen,
        };

        let res = await graphqlFetch({
            query: operate === "add" ? CreateApplicationType : UpdateApplicationType,
            variables: saveData,
            hashs: { pins: [app.atHash] },
        });
        if (res) {
            message.success("成功更新应用版本信息");
            loadApplications();
        }
    };

    const renderAlertDescription = (
        <div>
            {state.errorsInfo.map((item, index) => (
                <div key={index}>{item}</div>
            ))}
        </div>
    );

    const cardBodyHeight = windowInnerHeight - 90 - 20 - 54;

    return (
        <div style={{ margin: 10 }}>
            <SemiCard
                style={{ marginBottom: 10 }}
                title={<span style={{ lineHeight: "32px", fontSize: 15 }}>新应用信息</span>}
                headerExtraContent={
                    <Button icon={<IconRefresh />} onClick={() => loadApplications()}>
                        刷新
                    </Button>
                }
                headerStyle={{ padding: "10px 14px" }}
                shadows="always"
                bordered={false}
                bodyStyle={{ padding: 10, height: cardBodyHeight, overflow: "auto" }}
            >
                {state.errorsInfo.length > 0 && (
                    <Alert
                        message="警告信息"
                        description={renderAlertDescription}
                        type="warning"
                        showIcon
                        closable
                        style={{ marginBottom: 10 }}
                        onClose={() => (state.errorsInfo = [])}
                    />
                )}

                <Table
                    loading={state.loading}
                    title={() => <div style={{ fontWeight: 600 }}>新应用版本信息</div>}
                    bordered
                    pagination={false}
                    dataSource={state.newApplicationClients}
                    size="small"
                    rowKey={"aiUuid"}
                >
                    <Column title="序号" align="center" width={80} render={(_, r, index) => index + 1} />
                    <Column title="应用名称" dataIndex="aiName" align="left" />
                    <Column title="应用分类" dataIndex="aiClas" align="center" width={200} />
                    <Column title="适用对象" dataIndex="aiObje" align="center" width={200} />
                    <Column title="客户端类型" dataIndex="atType" align="center" width={200} />
                    <Column title="客户端版本号" dataIndex="atVeno" align="center" width={260} render={(_, r) => (r.oldVeno ? r.oldVeno + " => " + _ : _)} />
                    <Column
                        title="操作"
                        key="operations"
                        align="center"
                        width={100}
                        render={(_, r) => {
                            return r.operator === "add" ? (
                                <Popconfirm title="确认要添加该应用客户端信息吗？" onConfirm={() => handleUpdateApplicationType(r, "add")} placement="topRight">
                                    <a>添加</a>
                                </Popconfirm>
                            ) : (
                                <Popconfirm
                                    title="确认要更新该应用客户端信息吗？"
                                    onConfirm={() => handleUpdateApplicationType(r, "update")}
                                    placement="topRight"
                                >
                                    <a>更新</a>
                                </Popconfirm>
                            );
                        }}
                    />
                </Table>

                <div style={{ height: 10 }}></div>

                <Table
                    loading={state.loading}
                    title={() => <div style={{ fontWeight: 600 }}>新应用列表</div>}
                    bordered
                    pagination={false}
                    dataSource={state.newApplications}
                    size="small"
                    rowKey={"aiUuid"}
                >
                    <Column title="序号" align="center" width={80} render={(_, r, index) => index + 1} />
                    <Column title="应用名称" dataIndex="aiName" align="left" />
                    <Column title="应用分类" dataIndex="aiClas" align="center" width={200} />
                    <Column title="适用对象" dataIndex="aiObje" align="center" width={200} />
                    <Column title="授权开始日期" dataIndex="aiStda" align="center" width={120} />
                    <Column title="授权结束日期" dataIndex="aiEnda" align="center" width={120} />
                    <Column
                        title="授权状态"
                        align="center"
                        width={100}
                        render={(_, r, i) =>
                            r.aiEnda === null ? "无限期" : dayjs().isSameOrBefore(r.aiEnda, "D") ? "正常" : <div style={{ color: "red" }}>已过期</div>
                        }
                    />
                    <Column
                        title="操作"
                        key="operations"
                        align="center"
                        width={100}
                        render={(_, r) => (
                            <Popconfirm title="确认要添加该应用信息吗？" onConfirm={() => handleAddNewApplication(r)} placement="topRight">
                                <a>添加</a>
                            </Popconfirm>
                        )}
                    />
                </Table>
            </SemiCard>
        </div>
    );
};

export default NewApplications;
